package com.ezlcp.user.service;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ezlcp.commons.base.db.BaseDao;
import com.ezlcp.commons.base.db.BaseService;
import com.ezlcp.commons.base.entity.IUser;
import com.ezlcp.commons.base.entity.JsonResult;
import com.ezlcp.commons.service.impl.SuperServiceImpl;
import com.ezlcp.commons.tool.IdGenerator;
import com.ezlcp.commons.tool.StringUtils;
import com.ezlcp.commons.utils.ContextUtil;
import com.ezlcp.user.entity.*;
import com.ezlcp.user.mapper.*;
import jakarta.annotation.Resource;
import lombok.NonNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;


/**
 * [系统菜单表]业务服务类
 */
@Service
public class MenuServiceImpl extends SuperServiceImpl<MenuMapper, Menu> implements BaseService<Menu> {
    /**
     * s_group_menu表elements字段中的元素KEY属性名
     */
    private static final String ELEMENT_KEY_NAME = "elementKey";

    @Autowired
    private MenuMapper menuMapper;
    @Resource
    private GroupMapper groupMapper;
    @Resource
    private PageElementMapper pageElementMapper;
    @Resource
    private GroupMenuMapper groupMenuMapper;
    @Resource
    private TenantMenuMapper tenantMenuMapper;
    @Resource
    @Lazy
    private SettingsServiceImpl settingsService;

    /**
     * @param tenantId 公司ID
     * @return java.util.List<com.hkyctech.loan.core.entity.Menu>
     * @description: 公司用户获取公司所有菜单
     * @author Elwin ZHANG
     * @date 2022/5/11 10:23
     */
    public List<TenantMenu> getTenantAllMenus(@NonNull String tenantId) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("tenant_id", tenantId);
        List<TenantMenu> menus = tenantMenuMapper.selectList(wrapper);
        //如果取到值，则直接返回
        if (menus != null && menus.size() > 0) {
            return menus;
        }
        menus = new ArrayList<>();
        QueryWrapper<Menu> wrap2 = new QueryWrapper<>();
        wrap2.eq("status", 0);
        wrap2.orderByAsc("page_level", "sort");
        var initMenus = menuMapper.selectList(wrap2);
        if (initMenus == null) {
            return menus;
        }
        //如果没有获取到当前租户的菜单，则从系统菜单中复制一份
        for (Menu menu : initMenus) {
            TenantMenu tMenu = new TenantMenu();
            BeanUtils.copyProperties(menu, tMenu);
            tMenu.setId(IdGenerator.getIdStr());
            tMenu.setSeq(1);
            tMenu.setStatus((short) 1);
            tMenu.setTenantId(tenantId);
//            tMenu.setMenuId(menu.getMenuId());
//            tMenu.setMenuName(menu.getMenuName());
//            tMenu.setHkName(menu.getHkName());
//            tMenu.setEnName(menu.getEnName());
//            tMenu.setIcon(menu.getIcon());
//            tMenu.setParentId(menu.getParentId());
//            tMenu.setUrl(menu.getUrl());
//            tMenu.setComponent(menu.getComponent());
//            tMenu.setParams(menu.getParams());
//            tMenu.setNavUrl(menu.getNavUrl());
//            tMenu.setSort(menu.getSort());
//            tMenu.setPageLevel(menu.getPageLevel());
//            tMenu.setOther(menu.getOther());
//            tMenu.setHidden(menu.getHidden());
//            tMenu.setParentPath(menu.getParentPath());
//            tMenu.setIsDesign(menu.getIsDesign());
//            tMenu.setMenuType(menu.getMenuType());
//            tMenu.setIsCustom(menu.getIsCustom());
//            tMenu.setFrontType(menu.getFrontType());
            tenantMenuMapper.insert(tMenu);
        }
        return menus;
    }


    /***
     * @description: 获取平台的所有菜单
     * @return java.util.List<com.hkyctech.loan.core.entity.Menu>
     * @author Elwin ZHANG
     * @date 2022/5/11 13:41
     */
    public List<Menu> getPlatformMenus() {
        QueryWrapper<Menu> wrapper = new QueryWrapper<>();
        wrapper.lt("status", 4);
        wrapper.orderByAsc("sort");
        return menuMapper.selectList(wrapper);
    }

    /***
     * @description: 获取平台用户的授权菜单
     * @param userId 用户ID
     * @return java.util.List<com.hkyctech.loan.core.entity.Menu>
     * @author Elwin ZHANG
     * @date 2022/5/11 13:39
     */
    public List<Menu> getAdminUserMenus(String userId) {
        return menuMapper.getUserMenus(userId);
    }

    /**
     * @param userId   用户ID
     * @param tenantId 公司ID
     * @return java.util.List<com.hkyctech.loan.core.entity.Menu>
     * @description: 获取公司用户的授权菜单
     * @author Elwin ZHANG
     * @date 2022/6/9 9:53
     */
    public List<TenantMenu> getCommonUserMenus(String userId, String tenantId) {
        List<TenantMenu> menus = menuMapper.getCommonUserMenus(userId, tenantId);
        return menus;
    }

    /**
     * @param menuId   菜单ID
     * @param tenantId 公司ID
     * @return com.hkyctech.loan.core.entity.Menu
     * @description: 查询某个租户的菜单
     * @author Elwin ZHANG
     * @date 2022/6/9 11:56
     */
    public TenantMenu getTenantMenu(String menuId, String tenantId) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("tenant_id", tenantId);
        wrapper.eq("menu_id", menuId);
        return tenantMenuMapper.selectOne(wrapper);
    }

    /**
     * @param menu     菜单对象
     * @param tenantId 公司ID
     * @return com.hkyctech.loan.core.entity.Menu
     * @description: 更新某个租户的菜单
     * @author Elwin ZHANG
     * @date 2022/6/9 11:56
     */
    public void updateTenantMenu(TenantMenu menu, String tenantId) {
        tenantMenuMapper.updateById(menu);
    }

    /**
     * @param userId 用户ID
     * @param menuId 菜单ID
     * @return java.util.List<java.util.HashMap>
     * @description: 查询用户的某个菜单页面权限
     * @author Elwin ZHANG
     * @date 2022/5/11 14:30
     */
    public List<PageElement> getUserPageAuth(String userId, String menuId) {
        QueryWrapper<PageElement> wrapper = new QueryWrapper<>();
        wrapper.eq("menu_id", menuId);
        IUser user = ContextUtil.getCurrentUser();
        //超级管理员或公司管理员拥有所有权限，非管理员则查询授权
        if (user.isAdmin() || user.isStaff()) {
            List<GroupMenu> pageAuths = menuMapper.getUserPageAuth(userId, menuId);
            //没有授权，或菜单下没有控制到按钮
            if (pageAuths == null || pageAuths.size() == 0 || pageAuths.get(0).getHasElement() == 0) {
                return new ArrayList<>();
            }
            //合并所有授权的按钮或元素的KEY
            HashSet<String> setKeys = new HashSet<>();
            for (GroupMenu pageAuth : pageAuths) {
                String strElements = pageAuth.getElements();
                collectElements(setKeys, strElements);
            }
            //并没有授权相关的元素
            if (setKeys.size() == 0) {
                return new ArrayList<>();
            }
            //查询授权的元素信息
            wrapper.in("element_key", setKeys);
        }
        return pageElementMapper.selectList(wrapper);
    }

    /***
     * @description: 将JSON格式的页面元素KEY，加到集合中去重
     * @param setKeys 集合对象
     * @param strElements JSON格式的页面元素
     * @author Elwin ZHANG
     * @date 2022/6/21 10:24
     */
    private void collectElements(HashSet<String> setKeys, String strElements) {
        if (StringUtils.isEmpty(strElements) || "[]".equals(strElements)) {
            return;
        }
        try {
            JSONArray array = JSON.parseArray(strElements);
            for (int i = 0; i < array.size(); i++) {
                //JSONObject object=array.getJSONObject(i);
                //String key=object.getString(ELEMENT_KEY_NAME);
                String key = array.getString(i);
                if (StringUtils.isNotEmpty(key)) {
                    setKeys.add(key);
                }
            }
        } catch (Exception e) {
            log.warn("MenuService.collectElements解析JSON出错：" + strElements);
        }
    }

    /***
     * @description: 查询菜单页面元素
     * @param menuId 菜单ID，如果有则只取当前菜单的页面元素
     * @return java.util.List<com.hkyctech.loan.core.entity.PageElement>
     * @author Elwin ZHANG
     * @date 2022/5/11 10:52
     */
    public List<PageElement> getElements(String menuId) {
        QueryWrapper<PageElement> wrapper = new QueryWrapper<>();
        if (StringUtils.isNotEmpty(menuId)) {
            wrapper.eq("menu_id", menuId);
        }
        return pageElementMapper.selectList(wrapper);
    }

    /***
     * @description: 获取某用户组拥有的所有菜单权限
     * @param groupId 用户组ID
     * @author Elwin ZHANG
     * @date 2022/5/11 11:10
     */
    public List<GroupMenu> getGroupMenus(String groupId) {
        QueryWrapper<GroupMenu> wrapper = new QueryWrapper<>();
        if (StringUtils.isNotEmpty(groupId)) {
            wrapper.eq("group_id", groupId);
        }
        return groupMenuMapper.selectList(wrapper);
    }

    /***
     * @description: 修改用户组的菜单授权
     * @param  groupId 组IDID
     * @param array obj(menuId，elementId)
     * @author Elwin ZHANG
     * @date 2022/5/11 11:18
     */
    @Transactional(rollbackFor = Exception.class)
    public void editGroupMenus(String groupId, JSONArray array) {
        Group group = groupMapper.selectById(groupId);
        if (group == null) {
            return;
        }
        //取用户组关联的公司ID
        String tenantId = group.getTenantId();
        //删除当前用户组的旧的权限
        QueryWrapper<GroupMenu> wrapper = new QueryWrapper<>();
        wrapper.eq("group_id", groupId);
        groupMenuMapper.delete(wrapper);
        //插入新的授权
        for (int i = 0; i < array.size(); i++) {
            JSONObject object = array.getJSONObject(i);
            String menuId;
            String elements = "[]";
            Integer hasElement;
            //解析传入参数
            try {
                menuId = object.getString("menuId");
                hasElement = object.getInteger("hasElement");
                Object objElements = object.getJSONArray("elements");
                if (objElements != null) {
                    elements = JSON.toJSONString(objElements);
                }
            } catch (Exception e) {
                log.error("editGroupMenus解析JSON出错：" + JSON.toJSONString(object));
                throw new RuntimeException("editGroupMenus:解析JSON出错");
            }
            if (StringUtils.isEmpty(menuId)) {
                throw new RuntimeException("editGroupMenus:菜單ID不能為空");
            }
            if (hasElement == null) {
                hasElement = 0;
            }
            GroupMenu groupMenu = new GroupMenu();
            groupMenu.setId(IdGenerator.getIdStr());
            groupMenu.setHasElement(hasElement.shortValue());
            groupMenu.setMenuId(menuId);
            groupMenu.setGroupId(groupId);
            groupMenu.setElements(elements);
            groupMenu.setTenantId(tenantId);
            groupMenuMapper.insert(groupMenu);
        }
    }

    /***
     * @description 转换Menu列表为TenantMenu列表
     * @param menus Menu列表
     * @return java.util.List<com.ezlcp.user.entity.TenantMenu>
     * @author Elwin ZHANG
     * @date 2023/2/9 14:48
     */
    public List<TenantMenu> convert(@NonNull List<Menu> menus) {
        List<TenantMenu> result = new ArrayList<>();
        for (var menu : menus) {
            TenantMenu tMenu = new TenantMenu();
            BeanUtils.copyProperties(menu, tMenu);
            result.add(tMenu);
        }
        return result;
    }

    /***
     * @description: 获取某用户组的授权信息，用于用户组授权页
     * @param groupId 用户组ID
     * @author Elwin ZHANG
     * @date 2022/6/17 11:47
     */
    public JsonResult getGroupAuthInfo(String groupId) {
        IUser user = ContextUtil.getCurrentUser();
        if (user == null) {
            return JsonResult.Fail("menu.firstLogin");
        }
        //获取全部的菜单
        List<TenantMenu> lstMenus;
        if (user.isPlatformUser()) {
            var menus = getPlatformMenus();
            if (menus == null || menus.size() == 0) {
                return JsonResult.Fail("menu.gainFail");
            }
            lstMenus = convert(menus);
        } else {
            String tenantId = user.getTenantId();
            lstMenus = getTenantAllMenus(tenantId);
            if (lstMenus == null || lstMenus.size() == 0) {
                return JsonResult.Fail("menu.gainFail");
            }
        }
        //要返回的结果对象
        List<JSONObject> lstResult = new ArrayList<>();
        //用户组的菜单
        List<GroupMenu> groupMenus = getGroupMenus(groupId);
        //菜单的元素
        List<PageElement> elements = getElements(null);
        //循环处理，把实体对象转成JSON对象，方便增加新的属性
        for (var menu : lstMenus) {
            String menuId = menu.getMenuId();
            //隐藏的菜单忽略
            if (menu.getHidden() == 1 && menu.getIsDesign() == 0) {
                continue;
            }
            JSONObject objMenu = JSON.parseObject(JSON.toJSONString(menu));
            //菜单拥有的全部元素配置
            Object menuPageElements = elements.stream().filter(e -> e.getMenuId().equals(menuId)).collect(Collectors.toList());
            objMenu.put("pageElements", menuPageElements);
            //菜单当前授权的元素
            objMenu.put("checked", false);
            objMenu.put("curElements", new ArrayList<>());
            handleGroupMenuAuth(menuId, groupMenus, objMenu);
            lstResult.add(objMenu);
        }
        JsonResult result = JsonResult.Success("seriaNo.resetSuccess");
        result.setData(lstResult);
        result.setShow(false);
        return result;
    }

    /***
     * @description: 处理当前用户组菜单的授权
     * @param menuId 当前菜单ID
     * @param groupMenus 用户组的所有授权
     * @param objMenu 新的菜单对象
     * @author Elwin ZHANG
     * @date 2022/6/17 14:55
     */
    private void handleGroupMenuAuth(String menuId, List<GroupMenu> groupMenus, JSONObject objMenu) {
        if (groupMenus == null || groupMenus.size() == 0) {
            return;
        }
        for (GroupMenu groupMenu : groupMenus) {
            //找到当前菜单对应当前用户组的授权
            if (menuId.equals(groupMenu.getMenuId())) {
                objMenu.put("checked", true);
                String elements = groupMenu.getElements();
                if (StringUtils.isEmpty(elements) || "[]".equals(elements)) {
                    objMenu.put("curElements", new ArrayList<>());
                } else {
                    JSONArray array = JSON.parseArray(elements);
                    /**
                     ArrayList<String> al=new ArrayList<>();
                     for(int i=0;i<array.size();i++){
                     JSONObject object=array.getJSONObject(i);
                     al.add(object.getString(ELEMENT_KEY_NAME));
                     }*/
                    objMenu.put("curElements", array);
                }
                return;
            }
        }
    }

    /**
     * @param path 前端的路由
     * @return java.lang.String
     * @description: 根据前端的路由取对应的菜单名
     * @author Elwin ZHANG
     * @date 2022/6/14 18:22
     */
    public String getMenuName(String path) {
        if (StringUtils.isEmpty(path)) {
            return "";
        }
        String url = path;
        //取路径的最后一段
        if (path.contains("/")) {
            String[] arr = path.split("/");
            url = arr[arr.length - 1];
        }
        QueryWrapper<Menu> wrapper = new QueryWrapper<>();
        wrapper.eq("url", url);
        Menu menu = menuMapper.selectOne(wrapper);
        if (menu == null) {
            return "";
        }
        return menu.getMenuName();
    }

    @Override
    public BaseDao<Menu> getRepository() {
        return menuMapper;
    }
}